﻿using System;
using System.Collections.Generic;

namespace LT_CachePool
{
    /// <summary>
    /// 对象池条目行为
    /// </summary>
    public interface IPoolEntry
    {
        /// <summary>
        /// 当对象池条目取出
        /// </summary>
        public void OnTake();

        /// <summary>
        /// 当对象池条目回收
        /// </summary>
        public void OnRecycle();

        /// <summary>
        /// 条目释放
        /// </summary>
        public void OnRelase();
    }

    public abstract class AbsPoolEntry : IPoolEntry
    {
        public abstract void OnTake();

        public abstract void OnRecycle();

        public abstract void OnRelase();
    }

    public sealed class HyPool<T> where T : IPoolEntry
    {
        //空闲的条目
        private Queue<T> m_IdleEntrys = new Queue<T>();
        /// <summary>
        /// 所有条目缓存
        /// </summary>
        List<T> m_AllCacheEntrys = new List<T>();

        //默认生长长度
        private int m_GrowthCount;

        /// <summary>
        /// 生成缓存条目的HOOK方法
        /// </summary>
        public event Func<T> GeneratePoolEntryHook;

        public Queue<T> Entrys { get { return m_IdleEntrys; } }

        public HyPool(int growthCount)
        {
            m_GrowthCount = growthCount;
        }

        private void Growth()
        {
            for (int i = 0; i < m_GrowthCount; i++)
            {
                var entry = GeneratePoolEntryHook.Invoke();
                entry.OnRecycle();
                m_IdleEntrys.Enqueue(entry);
                m_AllCacheEntrys.Add(entry);
            }
        }

        public T Take()
        {
            if (m_IdleEntrys.Count == 0)
            {
                Growth();
            }
            var entry = m_IdleEntrys.Dequeue();
            entry.OnTake();
            return entry;
        }

        public void Recycle(T entry)
        {
            if (!m_IdleEntrys.Contains(entry))
            {
                entry.OnRecycle();
                m_IdleEntrys.Enqueue(entry);
            }
        }

        public void OnRelase()
        {
            foreach (var item in m_AllCacheEntrys)
            {
                item.OnRelase();
            }
            m_AllCacheEntrys = null;
            m_IdleEntrys = null;
        }
    }
}